﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Diagnostics;
using E4D.AppFabric.Entities;
using E4D.AppFabric.Entities.Engine;


namespace MDCAdminTool
{
    public abstract class PowerShellBase<TParent,TChild> : CacheEntityBase , IDisposable , ICacheCommand<TChild>
        where TChild : CacheEntityBase
    {
        #region Fields

        //protected static PowerShell powerShell;
        //protected static Runspace RunSpace;
        protected Dictionary<string, object> Params;

        public bool IsRunSpaceOpen { get; set; }
        public new TParent Parent { get; set; }
        #endregion

        protected PowerShellBase()
        {
            IsRunSpaceOpen = false;
            //OpenRunSpace();
        }
        ~PowerShellBase()
        {
            Dispose();
        }

        protected Collection<PSObject> Invoke(ISession session, string commandName)
        {
            return Invoke(session, commandName, new Dictionary<string, object>());
        }


        protected Collection<PSObject> Invoke(ISession session, string commandName, Dictionary<string, object> parameters)
        {
            Collection<PSObject> Result = null;
            AddResultToLog(new PowerShellCommand { CommandName = commandName, Parameters = parameters });

            try
            {
                Result = session.Invoke(commandName, parameters);

                InsertResultToOutput(Result);
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception.Message);
                if (Output != null)
                {
                    AddResultToLog(new ErrorMessage { Message = exception.Message });
                }
            }

            return Result;
        }

        void InsertResultToOutput( IEnumerable<PSObject> result )
        {
            foreach (var obj in result)
            {
                if ( Output != null && obj.BaseObject != null)
                {
                    if ( obj.BaseObject.GetType().Name == "HostCacheStats" )
                    {
                        AddResultToLog( obj.ConvertPSObjectToHostCacheStats() );
                    }
                    else if ( obj.BaseObject.GetType().Name == "NamedCacheStats" )
                    {
                        AddResultToLog( obj.ConvertPSObjectToNamedCacheStats() );
                    }
					else if (obj.BaseObject.GetType().Name == "ClusterHealth")
					{
                        foreach (var host in obj.ConvertPSObjectToClusterHealthStatus().Hosts)
                        {
                            this.AddResultToLog(host);
                            this.AddResultsToLog(host.Caches);
                        }
					}
                    else if ( obj.BaseObject.GetType().Name == "CacheConfig" )
                    {
                        AddResultToLog( obj.ConvertPSObjectToCacheConfig() );
                    }
                    else if ( obj.BaseObject.GetType().Name == "HostConfig" )
                    {
                        AddResultToLog( obj.ConvertPSObjectToHostConfig() );
                    }
                    else if ( obj.BaseObject.ToString().Contains("ErrorCode") )
                    {
                        AddResultToLog( new ErrorMessage{ Message =  obj.BaseObject.ToString() } );
                    }
                    else if (obj.BaseObject.ToString() != "") 
                    {
                        AddResultToLog( obj.BaseObject );
                    }
                    else
                    {
                        foreach (PSPropertyInfo value in obj.Properties)
                        {
                            Log(value.Name+"="+value.Value);
                        }
                    }
                }
            }
        }

        protected void AddResultToLog( object obj )
        {
            if( Output == null ) return;

            Log( obj );
        }

        protected void AddResultsToLog<T>(IEnumerable<T> results)
        {
            if (Output == null) return;

            foreach (var obj in results)
                Log(obj);
        }

        #region IDisposable Members
        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }

        #endregion

        #region ICacheCommand<TChild> Members
        public virtual void Add( TChild item )
        {
            Items.Add( item );
        }
        public virtual void Remove( TChild item )
        {
            Items.Remove(item);
        }
        public Collection<TChild> Items { get; set; }
        #endregion

    	protected void InvokeExpression(ISession session, string command)
    	{
    		var p = new Dictionary<string, object>();
    		p.Add("Command", command);

    		Invoke(session, "Invoke-Expression", p);
    	}
    }
}
